package com.triones.api.service.interlace.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.config.InterlaceConfig;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.PushNotificationEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.IdempotentKeyGenerator;
import com.ruoyi.common.utils.SnCreator;
import com.ruoyi.common.utils.StringUtils;
import com.triones.api.entity.CountryDictDO;
import com.triones.api.entity.FeeThaliDO;
import com.triones.api.entity.StateDictDO;
import com.triones.api.entity.interlace.bo.*;
import com.triones.api.entity.interlace.bo.request.*;
import com.triones.api.entity.interlace.dto.*;
import com.triones.api.entity.interlace.vo.*;
import com.triones.api.entity.vo.StateDictVO;
import com.triones.api.mapper.CountryDictMapper;
import com.triones.api.mapper.FeeThaliMapper;
import com.triones.api.mapper.StateDictMapper;
import com.triones.api.mapper.interlace.*;
import com.triones.api.service.interlace.InterlaceCommunalService;
import com.triones.api.service.interlace.InterlaceCryptoService;
import com.triones.api.service.interlace.PushService;
import com.triones.api.service.third.InterlaceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * interlace 加密货币相关接口
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InterlaceCryptoServiceImpl implements InterlaceCryptoService {

    @Value("${spring.profiles.active}")
    private String activeProfile;

    private final InterlaceService interlaceService;

    private final InterlaceConfig interlaceConfig;

    private final InterlaceCommunalService interlaceCommunalService;

    private final InterlaceBalancesMapper interlaceBalancesMapper;

    private final InterlaceWalletCurrencyChainMapper interlaceWalletCurrencyChainMapper;

    private final InterlaceCryptoWalletMapper interlaceCryptoWalletMapper;

    private final InterlaceTransfersFeeAndQuotaMapper interlaceTransfersFeeAndQuotaMapper;

    private final InterlaceTransfersFeesMapper interlaceTransfersFeesMapper;

    private final InterlaceTransfersMapper interlaceTransfersMapper;

    private final InterlaceEstimateQuoteMapper interlaceEstimateQuoteMapper;

    private final InterlaceKycMapper interlaceKycMapper;

    private final InterlaceMemberMapper interlaceMemberMapper;

    private final InterlaceInternalTransferMapper interlaceInternalTransferMapper;

    private final MasterBalanceMapper masterBalanceMapper;

    private final InterlaceCurrencyChainMapper interlaceCurrencyChainMapper;

    private final InterlaceBlockchainAddressCatalogueMapper interlaceBlockchainAddressCatalogueMapper;

    private final InterlaceQuantumTransferMapper interlaceQuantumTransferMapper;

    private final InterlaceBudgetMapper interlaceBudgetMapper;

    private final InterlaceQuantumTransferFeesMapper interlaceQuantumTransferFeesMapper;

    private final CountryDictMapper countryDictMapper;

    private final StateDictMapper stateDictMapper;

    private final FeeThaliMapper feeThaliMapper;

    private final PushService pushService;

    private final InterlaceWarningMapper interlaceWarningMapper;

    @Override
    public List<InterlaceBalancesVO> apiWalletCurrencyList() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        List<InterlaceBalancesVO> list = new ArrayList<>();
        InterlaceMemberDO memberDO = interlaceMemberMapper.selectById(loginUser.getUserId());
        if (memberDO == null) {
            throw new ServiceException("用户不存在！");
        }
        if (!"Passed".equals(memberDO.getInterlaceAccountKycStatus())) {
//            InterlaceBalancesVO usdc = new InterlaceBalancesVO();
//            usdc.setId(-1L);
//            usdc.setCurrency("USDC");
//            usdc.setVirtualAvailable(BigDecimal.ZERO);
//            usdc.setWalletType("CryptoAsset");
//            list.add(usdc);
//            InterlaceBalancesVO usdt = new InterlaceBalancesVO();
//            usdt.setId(-1L);
//            usdt.setCurrency("USDT");
//            usdt.setVirtualAvailable(BigDecimal.ZERO);
//            usdt.setWalletType("CryptoAsset");
//            list.add(usdt);
//            InterlaceBalancesVO usd = new InterlaceBalancesVO();
//            usd.setId(-1L);
//            usd.setCurrency("USD");
//            usd.setAvailable(BigDecimal.ZERO);
//            usd.setWalletType("Budget");
//            list.add(usd);
        } else {
            list = interlaceBalancesMapper.selectVoList(new LambdaQueryWrapper<InterlaceBalancesDO>()
                .eq(InterlaceBalancesDO::getUid, loginUser.getUserId())
                .and(qr ->
                    qr.eq(InterlaceBalancesDO::getWalletType, "CryptoAsset")
                        .ne(InterlaceBalancesDO::getCurrency, "USD")
                        .or()
                        .eq(InterlaceBalancesDO::getWalletType, "Budget")
                        .eq(InterlaceBalancesDO::getCurrency, "USD")
                ).in(InterlaceBalancesDO::getCurrency, "USDC", "USDT", "USD")
            );
        }
        return list;
    }

    @Override
    public List<InterlaceCurrencyChainVO> apiWalletCurrencyChainList(String currency) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        return interlaceCurrencyChainMapper.selectVoList(new LambdaQueryWrapper<InterlaceCurrencyChainDO>()
            .eq(InterlaceCurrencyChainDO::getCurrency, currency)
            .eq(InterlaceCurrencyChainDO::getEnv, activeProfile));
    }

    @Override
    public InterlaceWalletCurrencyChainDO apiWalletCurrencyChainDetail(Long id, String chain) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }

        /** 查询余额信息 */
        InterlaceBalancesDO interlaceBalancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
            .eq(InterlaceBalancesDO::getId, id)
            .last("FOR UPDATE"));

        if (interlaceBalancesDO == null) {
            throw new ServiceException("没有查询到该币种的钱包信息！");
        }
        if (interlaceBalancesDO.getWalletId() == null || "".equals(interlaceBalancesDO.getWalletId())) {
            throw new ServiceException("没有查询到该币种的钱包信息！");
        }
        InterlaceWalletCurrencyChainDO walletCurrencyChainDO = interlaceWalletCurrencyChainMapper.selectOne(new LambdaQueryWrapper<InterlaceWalletCurrencyChainDO>()
            .eq(InterlaceWalletCurrencyChainDO::getChain, chain)
            .eq(InterlaceWalletCurrencyChainDO::getCurrency, interlaceBalancesDO.getCurrency())
            .eq(InterlaceWalletCurrencyChainDO::getUid, loginUser.getUserId()));
        if (walletCurrencyChainDO == null) {
            walletCurrencyChainDO = new InterlaceWalletCurrencyChainDO();
            walletCurrencyChainDO.setUid(loginUser.getUserId());
            walletCurrencyChainDO.setWalletId(interlaceBalancesDO.getWalletId());
            walletCurrencyChainDO.setCurrency(interlaceBalancesDO.getCurrency());
            walletCurrencyChainDO.setChain(chain);
            walletCurrencyChainDO.setCreateTime(System.currentTimeMillis());
            CryptoconnectWalletsAddressesRequest addressesRequest = new CryptoconnectWalletsAddressesRequest();
            addressesRequest.setChain(chain);
            addressesRequest.setCurrency(interlaceBalancesDO.getCurrency());
            Map response = interlaceService.cryptoconnectWalletsAddresses(addressesRequest, interlaceBalancesDO.getWalletId());
            if (response != null) {
                walletCurrencyChainDO.setAddress(Convert.toStr(response.get("address")));
                walletCurrencyChainDO.setSelected((Boolean) response.get("selected") ? 1 : 0);
                interlaceWalletCurrencyChainMapper.insert(walletCurrencyChainDO);
            } else {
                throw new ServiceException("获取区块链地址失败");
            }
        } else {
            if (walletCurrencyChainDO.getAddress() == null || walletCurrencyChainDO.getAddress().equals("")) {
                CryptoconnectWalletsAddressesRequest addressesRequest = new CryptoconnectWalletsAddressesRequest();
                addressesRequest.setChain(chain);
                addressesRequest.setCurrency(interlaceBalancesDO.getCurrency());
                Map response = interlaceService.cryptoconnectWalletsAddresses(addressesRequest, interlaceBalancesDO.getWalletId());
                if (response != null) {
                    walletCurrencyChainDO.setAddress(Convert.toStr(response.get("address")));
                    walletCurrencyChainDO.setSelected((Boolean) response.get("selected") ? 1 : 0);
                    interlaceWalletCurrencyChainMapper.updateById(walletCurrencyChainDO);
                } else {
                    throw new ServiceException("获取区块链地址失败");
                }
            }
        }
        return walletCurrencyChainDO;
    }

    @Override
    public CustomInterlaceTransfersFeeAndQuotaVO transfersFeeAndQuota(InterlaceTransfersFeeAndQuotaBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        InterlaceCryptoWalletVO interlaceWalletVO = interlaceCryptoWalletMapper.selectVoOne(new LambdaQueryWrapper<InterlaceCryptoWalletDO>()
            .eq(InterlaceCryptoWalletDO::getUid, loginUser.getUserId())
            .eq(InterlaceCryptoWalletDO::getCurrency, bo.getCurrency()));
        if (interlaceWalletVO == null) {
            throw new ServiceException("当前用户没有绑定钱包");
        }

        /** 查询提币交易手续费 */
        FeeThaliDO feeThali = feeThaliMapper.selectOne(new LambdaQueryWrapper<FeeThaliDO>()
            .eq(FeeThaliDO::getType, "crypto_withdraw")
            .eq(FeeThaliDO::getStatus, "0")
            .last("limit 1"));
        BigDecimal cryptoWithdrawFee = BigDecimal.ZERO;
        if (feeThali != null) {
            cryptoWithdrawFee = Convert.toBigDecimal(feeThali.getFeeConfig(), BigDecimal.ZERO);
        }

        /** 查询用户同种链以及地址 */
        InterlaceWalletCurrencyChainDO sourceWalletCurrencyChainDO = interlaceWalletCurrencyChainMapper.selectOne(new LambdaQueryWrapper<InterlaceWalletCurrencyChainDO>()
            .eq(InterlaceWalletCurrencyChainDO::getWalletId, interlaceWalletVO.getWalletId())
            .eq(InterlaceWalletCurrencyChainDO::getChain, bo.getDestinationChain())
            .eq(InterlaceWalletCurrencyChainDO::getCurrency, bo.getCurrency()));
        if (sourceWalletCurrencyChainDO == null) {
            throw new ServiceException("当前用户没有创建该链上的地址，请先创建该链上地址");
        }
        CustomInterlaceTransfersFeeAndQuotaVO vo = new CustomInterlaceTransfersFeeAndQuotaVO();
        List<InterlaceTransfersFeesDO> items = new ArrayList<>();
        /** 查询是否为内部之间划转 */
        InterlaceWalletCurrencyChainVO destinationInterlaceWalletCurrencyChainVO = interlaceWalletCurrencyChainMapper.selectVoOne(new LambdaQueryWrapper<InterlaceWalletCurrencyChainDO>()
            .eq(InterlaceWalletCurrencyChainDO::getCurrency, bo.getCurrency())
            .eq(InterlaceWalletCurrencyChainDO::getChain, bo.getDestinationChain())
            .eq(InterlaceWalletCurrencyChainDO::getAddress, bo.getDestinationAddress()));
        if (destinationInterlaceWalletCurrencyChainVO != null) {
            InterlaceCryptoWalletVO destinationInterlaceWalletVO = interlaceCryptoWalletMapper.selectVoOne(new LambdaQueryWrapper<InterlaceCryptoWalletDO>()
                .eq(InterlaceCryptoWalletDO::getWalletId, destinationInterlaceWalletCurrencyChainVO.getWalletId())
                .eq(InterlaceCryptoWalletDO::getUid, destinationInterlaceWalletCurrencyChainVO.getUid()));
            if (destinationInterlaceWalletVO != null) {
                InterlaceTransfersFeeAndQuotaDO transfersFeeAndQuotaDO = new InterlaceTransfersFeeAndQuotaDO();
                transfersFeeAndQuotaDO.setUid(loginUser.getUserId());
                transfersFeeAndQuotaDO.setSourceType("crypto_assets");
                transfersFeeAndQuotaDO.setSourceWalletId(interlaceWalletVO.getInterlaceAccountId());
                transfersFeeAndQuotaDO.setSourceChain(sourceWalletCurrencyChainDO.getChain());
                transfersFeeAndQuotaDO.setSourceAddress(sourceWalletCurrencyChainDO.getAddress());
                transfersFeeAndQuotaDO.setDestinationType("crypto_assets");
                transfersFeeAndQuotaDO.setDestinationChain(bo.getDestinationChain());
                transfersFeeAndQuotaDO.setDestinationAddress(bo.getDestinationAddress());
                transfersFeeAndQuotaDO.setDestinationAccountId(destinationInterlaceWalletVO.getInterlaceAccountId());
                transfersFeeAndQuotaDO.setCurrency(bo.getCurrency());
                transfersFeeAndQuotaDO.setAmount(bo.getAmount());
                transfersFeeAndQuotaDO.setCrossChainQuota(BigDecimal.ZERO);
                transfersFeeAndQuotaDO.setCrossChainFeeRate(BigDecimal.ZERO);
                transfersFeeAndQuotaDO.setCrossChainAmount(BigDecimal.ZERO);
                transfersFeeAndQuotaDO.setCreateTime(System.currentTimeMillis());
                interlaceTransfersFeeAndQuotaMapper.insert(transfersFeeAndQuotaDO);
                InterlaceTransfersFeesDO item = new InterlaceTransfersFeesDO();
                item.setTid(transfersFeeAndQuotaDO.getId());
                item.setCurrency(bo.getCurrency());
                item.setAmount(cryptoWithdrawFee);
                item.setType("crypto_withdraw");
                items.add(item);
                interlaceTransfersFeesMapper.insert(item);
                BeanUtil.copyProperties(transfersFeeAndQuotaDO, vo);
                vo.setItems(BeanUtil.copyToList(items, InterlaceTransfersFeesVO.class));
                return vo;
            }
        }
        TransfersFeeAndQuotaRequest request = new TransfersFeeAndQuotaRequest();
        TransfersFeeAndQuotaAmountRequest amountRequest = new TransfersFeeAndQuotaAmountRequest();
        amountRequest.setCurrency(bo.getCurrency());
        amountRequest.setAmount(Convert.toStr(bo.getAmount().subtract(cryptoWithdrawFee)));
        TransfersFeeAndQuotaSourceRequest sourceRequest = new TransfersFeeAndQuotaSourceRequest();
        sourceRequest.setType("cryptoconnect_wallet");
        sourceRequest.setId(interlaceWalletVO.getWalletId());
        TransfersFeeAndQuotaDestinationRequest destinationRequest = new TransfersFeeAndQuotaDestinationRequest();
        destinationRequest.setType("blockchain");
        destinationRequest.setChain(bo.getDestinationChain());
        destinationRequest.setAddress(bo.getDestinationAddress());
        request.setAccountId(interlaceWalletVO.getInterlaceAccountId());
        request.setAmount(amountRequest);
        request.setSource(sourceRequest);
        request.setDestination(destinationRequest);
        Map response = interlaceService.transfersFeeAndQuota(request);
        InterlaceTransfersFeeAndQuotaDO transfersFeeAndQuotaDO = new InterlaceTransfersFeeAndQuotaDO();
        if (response != null) {
            transfersFeeAndQuotaDO.setUid(loginUser.getUserId());
            transfersFeeAndQuotaDO.setSourceType("cryptoconnect_wallet");
            transfersFeeAndQuotaDO.setSourceWalletId(interlaceWalletVO.getWalletId());
            transfersFeeAndQuotaDO.setSourceChain(sourceWalletCurrencyChainDO.getChain());
            transfersFeeAndQuotaDO.setSourceAddress(sourceWalletCurrencyChainDO.getAddress());
            transfersFeeAndQuotaDO.setDestinationType("blockchain");
            transfersFeeAndQuotaDO.setDestinationChain(bo.getDestinationChain());
            transfersFeeAndQuotaDO.setDestinationAddress(bo.getDestinationAddress());
            transfersFeeAndQuotaDO.setCurrency(bo.getCurrency());
            transfersFeeAndQuotaDO.setAmount(bo.getAmount());
            transfersFeeAndQuotaDO.setCrossChainQuota(Convert.toBigDecimal(response.get("crossChainQuota")));
            transfersFeeAndQuotaDO.setCrossChainFeeRate(Convert.toBigDecimal(response.get("crossChainFeeRate")));
            transfersFeeAndQuotaDO.setCrossChainAmount(Convert.toBigDecimal(response.get("crossChainAmount")));
            transfersFeeAndQuotaDO.setCreateTime(System.currentTimeMillis());
            interlaceTransfersFeeAndQuotaMapper.insert(transfersFeeAndQuotaDO);
            List<Map> fees = (List<Map>) response.get("fees");
            InterlaceTransfersFeesDO transfersFeesDO = new InterlaceTransfersFeesDO();
            transfersFeesDO.setTid(transfersFeeAndQuotaDO.getId());
            transfersFeesDO.setCurrency(bo.getCurrency());
            transfersFeesDO.setAmount(cryptoWithdrawFee);
            transfersFeesDO.setType("crypto_withdraw");
            items.add(transfersFeesDO);
            if (fees != null && fees.size() > 0) {
                for (Map fee : fees) {
                    InterlaceTransfersFeesDO item = new InterlaceTransfersFeesDO();
                    item.setTid(transfersFeeAndQuotaDO.getId());
                    item.setCurrency(Convert.toStr(fee.get("currency")));
                    item.setAmount(Convert.toBigDecimal(fee.get("amount")));
                    item.setType(Convert.toStr(fee.get("type")));
                    items.add(item);
                }
            }
            interlaceTransfersFeesMapper.insertBatch(items);
        }
        BeanUtil.copyProperties(transfersFeeAndQuotaDO, vo);
        vo.setItems(BeanUtil.copyToList(items, InterlaceTransfersFeesVO.class));
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean transfers(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        InterlaceTransfersFeeAndQuotaVO transfersFeeAndQuotaVO = interlaceTransfersFeeAndQuotaMapper.selectVoById(id);
        if (transfersFeeAndQuotaVO == null) {
            throw new ServiceException("未查询到询价记录！");
        }
        InterlaceBalancesDO balancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
            .eq(InterlaceBalancesDO::getUid, loginUser.getUserId())
            .eq(InterlaceBalancesDO::getCurrency, transfersFeeAndQuotaVO.getCurrency())
            .last("FOR UPDATE"));
        if (balancesDO == null) {
            throw new ServiceException("当前用户没有绑定钱包");
        }
        List<InterlaceTransfersFeesVO> transfersItemVOS = interlaceTransfersFeesMapper.selectVoList(new LambdaQueryWrapper<InterlaceTransfersFeesDO>()
            .eq(InterlaceTransfersFeesDO::getTid, transfersFeeAndQuotaVO.getId()));
        BigDecimal feeAmount = BigDecimal.ZERO;
        BigDecimal cryptoWithdrawFee = BigDecimal.ZERO;
        if (transfersItemVOS != null && transfersItemVOS.size() > 0) {
            for (InterlaceTransfersFeesVO itemVO : transfersItemVOS) {
                feeAmount = feeAmount.add(itemVO.getAmount());
                if ("crypto_withdraw".equals(itemVO.getType())) {
                    cryptoWithdrawFee = itemVO.getAmount();
                }
            }
        }
        BigDecimal amount = transfersFeeAndQuotaVO.getAmount();
        BigDecimal deductAfter = amount.subtract(cryptoWithdrawFee);
        BigDecimal finalAmount = amount.subtract(feeAmount);
        if (!interlaceCommunalService.checkBalances(balancesDO, amount)) {
            throw new SecurityException("余额不足！");
        }
        /** 内部资产转移 */
        if (transfersFeeAndQuotaVO.getSourceType().equals("crypto_assets")) {

            /** 更新子主加密钱包 */
            interlaceCommunalService.updateCryptoWallet(transfersFeeAndQuotaVO.getSourceWalletId(), transfersFeeAndQuotaVO.getCurrency(), amount, "decrease");

            /** 保存己方转移记录 */
            InterlaceTransfersDO sourceTransfers = new InterlaceTransfersDO();
            sourceTransfers.setScene("crypto_assets_out");
            sourceTransfers.setUid(loginUser.getUserId());
            sourceTransfers.setAccountId(transfersFeeAndQuotaVO.getSourceWalletId());
            sourceTransfers.setSourceType(transfersFeeAndQuotaVO.getSourceType());
            sourceTransfers.setSourceWalletId(transfersFeeAndQuotaVO.getSourceWalletId());
            sourceTransfers.setSourceChain(transfersFeeAndQuotaVO.getSourceChain());
            sourceTransfers.setSourceAddress(transfersFeeAndQuotaVO.getSourceAddress());
            sourceTransfers.setSourceCurrency(transfersFeeAndQuotaVO.getCurrency());
            sourceTransfers.setSourceAmount(amount);
            sourceTransfers.setDestinationType(transfersFeeAndQuotaVO.getDestinationType());
            sourceTransfers.setDestinationWalletId(transfersFeeAndQuotaVO.getDestinationAccountId());
            sourceTransfers.setDestinationChain(transfersFeeAndQuotaVO.getDestinationChain());
            sourceTransfers.setDestinationAddress(transfersFeeAndQuotaVO.getDestinationAddress());
            sourceTransfers.setDestinationCurrency(transfersFeeAndQuotaVO.getCurrency());
            sourceTransfers.setDestinationAmount(finalAmount);
            sourceTransfers.setStatus("Closed");
            sourceTransfers.setCreateTime(System.currentTimeMillis());
            sourceTransfers.setUpdateTime(System.currentTimeMillis());
            sourceTransfers.setSn(SnCreator.generateCTSn());
            interlaceTransfersMapper.insert(sourceTransfers);
            /** 保存手续费记录 */
            InterlaceTransfersFeesDO transfersFees = new InterlaceTransfersFeesDO();
            transfersFees.setAmount(cryptoWithdrawFee);
            transfersFees.setCurrency(transfersFeeAndQuotaVO.getCurrency());
            transfersFees.setType("crypto_withdraw");
            transfersFees.setTid(sourceTransfers.getId());
            interlaceTransfersFeesMapper.insert(transfersFees);

            /** 目标用户钱包更新 */
            InterlaceBalancesDO destinationBalances = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
                .eq(InterlaceBalancesDO::getInterlaceAccountId, transfersFeeAndQuotaVO.getDestinationAccountId())
                .eq(InterlaceBalancesDO::getCurrency, transfersFeeAndQuotaVO.getCurrency())
                .eq(InterlaceBalancesDO::getWalletType, "CryptoAsset")
                .last("FOR UPDATE"));
            if (destinationBalances != null) {
                /** 更新子主加密钱包 */
                interlaceCommunalService.updateCryptoWallet(destinationBalances.getInterlaceAccountId(), transfersFeeAndQuotaVO.getCurrency(), finalAmount, "increase");

                /** 保存接收方转移记录 */
                InterlaceTransfersDO destinationTransfers = new InterlaceTransfersDO();
                destinationTransfers.setScene("crypto_assets_in");
                destinationTransfers.setUid(destinationBalances.getUid());
                destinationTransfers.setAccountId(destinationBalances.getInterlaceAccountId());
                destinationTransfers.setSourceType(transfersFeeAndQuotaVO.getSourceType());
                destinationTransfers.setSourceWalletId(transfersFeeAndQuotaVO.getSourceWalletId());
                destinationTransfers.setSourceChain(transfersFeeAndQuotaVO.getSourceChain());
                destinationTransfers.setSourceAddress(transfersFeeAndQuotaVO.getSourceAddress());
                destinationTransfers.setSourceCurrency(transfersFeeAndQuotaVO.getCurrency());
                destinationTransfers.setSourceAmount(finalAmount);
                destinationTransfers.setDestinationType(transfersFeeAndQuotaVO.getDestinationType());
                destinationTransfers.setDestinationWalletId(transfersFeeAndQuotaVO.getDestinationAccountId());
                destinationTransfers.setDestinationChain(transfersFeeAndQuotaVO.getDestinationChain());
                destinationTransfers.setDestinationAddress(transfersFeeAndQuotaVO.getDestinationAddress());
                destinationTransfers.setDestinationCurrency(transfersFeeAndQuotaVO.getCurrency());
                destinationTransfers.setDestinationAmount(finalAmount);
                destinationTransfers.setStatus("Closed");
                destinationTransfers.setCreateTime(System.currentTimeMillis());
                destinationTransfers.setUpdateTime(System.currentTimeMillis());
                destinationTransfers.setSn(SnCreator.generateCTSn());
                interlaceTransfersMapper.insert(destinationTransfers);

                /** 推送-账户余额变动提醒 */
                if (amount.compareTo(BigDecimal.valueOf(500)) > 0) {
                    String pushType = "account_balance_change";
                    PushNotificationEnum notification = PushNotificationEnum.fromPushType(pushType);
                    String zhContent = notification.getZhContent();
                    zhContent = MessageFormat.format(zhContent, amount, transfersFeeAndQuotaVO.getCurrency());
                    String enContent = notification.getEnContent();
                    enContent = MessageFormat.format(enContent, amount, transfersFeeAndQuotaVO.getCurrency());
                    String jaContent = notification.getJaContent();
                    jaContent = MessageFormat.format(jaContent, amount, transfersFeeAndQuotaVO.getCurrency());
                    pushService.push(pushType, zhContent, enContent, jaContent, loginUser.getUserId());
                }

                /** 推送-提现交易成功通知 */
                String pushType = "withdrawal_success";
                PushNotificationEnum notification = PushNotificationEnum.fromPushType(pushType);
                String zhContent = notification.getZhContent();
                zhContent = MessageFormat.format(zhContent, amount, transfersFeeAndQuotaVO.getCurrency());
                String enContent = notification.getEnContent();
                enContent = MessageFormat.format(enContent, amount, transfersFeeAndQuotaVO.getCurrency());
                String jaContent = notification.getJaContent();
                jaContent = MessageFormat.format(jaContent, amount, transfersFeeAndQuotaVO.getCurrency());
                pushService.push(pushType, zhContent, enContent, jaContent, loginUser.getUserId());
            }
        } else {
            /** 提取到外部账户地址（发起交易） */
            /** 1、发起主加密账户转移->子加密货币账户 */
            HandleInternalTransferCryptoBO transferCrypto = new HandleInternalTransferCryptoBO();
            transferCrypto.setDestinationAccountId(balancesDO.getInterlaceAccountId());
            transferCrypto.setCurrency(transfersFeeAndQuotaVO.getCurrency());
            transferCrypto.setAmount(deductAfter);
            InterlaceInternalTransferDO transferDO = this.masterWalletToCryptoAssets(transferCrypto);
            if (transferDO != null) {
                Map transfersResponse = null;
                String idempotencyKey = IdempotentKeyGenerator.generateIdempotentKey();
                try {
                    /** 发起转移 */
                    TransfersRequest transfersRequest = new TransfersRequest();
                    transfersRequest.setIdempotencyKey(idempotencyKey);
                    TransfersFeeAndQuotaSourceRequest sourceRequest = new TransfersFeeAndQuotaSourceRequest();
                    sourceRequest.setType(transfersFeeAndQuotaVO.getSourceType());
                    sourceRequest.setId(balancesDO.getWalletId());
                    TransfersFeeAndQuotaDestinationRequest destinationRequest = new TransfersFeeAndQuotaDestinationRequest();
                    destinationRequest.setType(transfersFeeAndQuotaVO.getDestinationType());
                    destinationRequest.setChain(transfersFeeAndQuotaVO.getDestinationChain());
                    destinationRequest.setAddress(transfersFeeAndQuotaVO.getDestinationAddress());
                    TransfersFeeAndQuotaAmountRequest amountRequest = new TransfersFeeAndQuotaAmountRequest();
                    amountRequest.setCurrency(transfersFeeAndQuotaVO.getCurrency());
                    amountRequest.setAmount(Convert.toStr(deductAfter));
                    transfersRequest.setAccountId(balancesDO.getInterlaceAccountId());
                    transfersRequest.setSource(sourceRequest);
                    transfersRequest.setDestination(destinationRequest);
                    transfersRequest.setAmount(amountRequest);
                    transfersResponse = interlaceService.transfers(transfersRequest);
                } catch (Exception e) {
                    /** 发起子加密货币账户->主加密账户转移 */
                    HandleInternalTransferCryptoBO transferCryptoBO = new HandleInternalTransferCryptoBO();
                    transferCryptoBO.setSourceAccountId(balancesDO.getInterlaceAccountId());
                    transferCryptoBO.setCurrency(transfersFeeAndQuotaVO.getCurrency());
                    transferCryptoBO.setAmount(deductAfter);
                    this.cryptoAssetsToMasterWallet(transferCryptoBO);
                    return false;
                }
                List<InterlaceTransfersFeesDO> items = new ArrayList<>();
                if (transfersResponse != null) {
                    InterlaceTransfersDO transfersDO = new InterlaceTransfersDO();
                    transfersDO.setScene("assets_withdrawal");
                    transfersDO.setStatus(Convert.toStr(transfersResponse.get("status")));
                    transfersDO.setRid(Convert.toStr(transfersResponse.get("id")));
                    transfersDO.setCreateTime(System.currentTimeMillis());
                    transfersDO.setUpdateTime(System.currentTimeMillis());
                    transfersDO.setIdempotencyKey(idempotencyKey);
                    transfersDO.setUid(loginUser.getUserId());
                    transfersDO.setSourceCurrency(transfersFeeAndQuotaVO.getCurrency());
                    transfersDO.setSourceType(transfersFeeAndQuotaVO.getSourceType());
                    transfersDO.setSourceWalletId(balancesDO.getWalletId());
                    transfersDO.setSourceAmount(amount);
                    Map sourceResponse = (Map) transfersResponse.get("source");
                    if (sourceResponse != null) {
                        transfersDO.setSourceChain(Convert.toStr(sourceResponse.get("chain")));
                        transfersDO.setSourceAddress(Convert.toStr(sourceResponse.get("address")));
                    }
                    Map destinationResponse = (Map) transfersResponse.get("destination");
                    if (destinationResponse != null) {
                        transfersDO.setDestinationWalletId(Convert.toStr(destinationResponse.get("id")));
                    }
                    transfersDO.setDestinationType(transfersFeeAndQuotaVO.getDestinationType());
                    transfersDO.setDestinationChain(transfersFeeAndQuotaVO.getDestinationChain());
                    transfersDO.setDestinationAddress(transfersFeeAndQuotaVO.getDestinationAddress());
                    transfersDO.setDestinationCurrency(transfersFeeAndQuotaVO.getCurrency());
                    transfersDO.setDestinationAmount(finalAmount);
                    transfersDO.setSn(SnCreator.generateCTSn());
                    interlaceTransfersMapper.insert(transfersDO);
                    List<Map> feesResponseList = (List<Map>) transfersResponse.get("fees");
                    if (feesResponseList != null && feesResponseList.size() > 0) {
                        for (Map map : feesResponseList) {
                            InterlaceTransfersFeesDO itemDO = new InterlaceTransfersFeesDO();
                            itemDO.setTid(transfersDO.getId());
                            itemDO.setCurrency(Convert.toStr(map.get("currency")));
                            itemDO.setAmount(Convert.toBigDecimal(map.get("amount")));
                            itemDO.setType(Convert.toStr(map.get("type")));
                            itemDO.setCreateTime(System.currentTimeMillis());
                            items.add(itemDO);
                        }
                    }
                    InterlaceTransfersFeesDO transfersFees = new InterlaceTransfersFeesDO();
                    transfersFees.setAmount(cryptoWithdrawFee);
                    transfersFees.setCurrency(transfersFeeAndQuotaVO.getCurrency());
                    transfersFees.setType("crypto_withdraw");
                    transfersFees.setTid(transfersDO.getId());
                    items.add(transfersFees);
                    interlaceTransfersFeesMapper.insertBatch(items);

                    /** 更新子主加密钱包 */
                    interlaceCommunalService.updateCryptoWallet(balancesDO.getInterlaceAccountId(), transfersFeeAndQuotaVO.getCurrency(), amount, "decrease");

                    /** 推送-账户余额变动提醒 */
                    if (amount.compareTo(BigDecimal.valueOf(500)) > 0) {
                        String pushType = "account_balance_change";
                        PushNotificationEnum notification = PushNotificationEnum.fromPushType(pushType);
                        String zhContent = notification.getZhContent();
                        zhContent = MessageFormat.format(zhContent, amount, transfersFeeAndQuotaVO.getCurrency());
                        String enContent = notification.getEnContent();
                        enContent = MessageFormat.format(enContent, amount, transfersFeeAndQuotaVO.getCurrency());
                        String jaContent = notification.getJaContent();
                        jaContent = MessageFormat.format(jaContent, amount, transfersFeeAndQuotaVO.getCurrency());
                        pushService.push(pushType, zhContent, enContent, jaContent, loginUser.getUserId());
                    }

                    /** 推送-提现/转账申请通知 */
                    String pushType = "withdrawal_or_transfer_request";
                    PushNotificationEnum notification = PushNotificationEnum.fromPushType(pushType);
                    String zhContent = notification.getZhContent();
                    zhContent = MessageFormat.format(zhContent, transfersDO.getSourceAmount(), transfersDO.getSourceCurrency());
                    String enContent = notification.getEnContent();
                    enContent = MessageFormat.format(enContent, transfersDO.getSourceAmount(), transfersDO.getSourceCurrency());
                    String jaContent = notification.getJaContent();
                    jaContent = MessageFormat.format(jaContent, transfersDO.getSourceAmount(), transfersDO.getSourceCurrency());
                    pushService.push(pushType, zhContent, enContent, jaContent, loginUser.getUserId());
                }
            } else {
                throw new ServiceException("系统正在更新资金池，请稍后重试!");
            }
        }
        return true;
    }

    @Override
    public InterlaceEstimateQuoteDO estimateQuote(InterlaceEstimateQuoteBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        InterlaceMemberVO memberVO = interlaceMemberMapper.selectVoById(loginUser.getUserId());
        if (memberVO == null) {
            throw new SecurityException("用户信息不存在！");
        }
        /** 获取换汇手续费 */
        FeeThaliDO feeThaliDO = feeThaliMapper.selectOne(new LambdaQueryWrapper<FeeThaliDO>()
            .eq(FeeThaliDO::getType, "quote")
            .eq(FeeThaliDO::getStatus, "0")
            .last("limit 1"));
        BigDecimal quoteFee = BigDecimal.ZERO;
        if (feeThaliDO != null) {
            quoteFee = Convert.toBigDecimal(feeThaliDO.getFeeConfig()).divide(BigDecimal.valueOf(100), 6, BigDecimal.ROUND_HALF_UP);
        }
        quoteFee = quoteFee.multiply(bo.getRfqAmount());
        /** 查询当前环境支持的比加密货币 */
        List<String> currencyList = interlaceWalletCurrencyChainMapper.selectCurrencyList(activeProfile);
        if (currencyList != null && currencyList.size() > 0) {
            if (!currencyList.contains(bo.getBaseCurrency())) {
                throw new ServiceException("当前环境不支持该币种！");
            }
        }
        if (!bo.getQuoteCurrency().equals("USD")) {
            throw new ServiceException("当前环境不支持除了USD以外的货币！");
        }
        if (!(bo.getSide().equals("buy") || bo.getSide().equals("sell"))) {
            throw new ServiceException("请传入正确的买卖类型！");
        }
        EstimateQuoteRequest request = new EstimateQuoteRequest();
        BeanUtil.copyProperties(bo, request);
        request.setAccountId(memberVO.getInterlaceAccountId());
        Map estimateQuoteResponse = interlaceService.estimateQuote(request);
        if (estimateQuoteResponse != null) {
            BigDecimal fee = Convert.toBigDecimal(estimateQuoteResponse.get("fee"));
            InterlaceEstimateQuoteDO interlaceEstimateQuoteDO = BeanUtil.toBean(bo, InterlaceEstimateQuoteDO.class);
            interlaceEstimateQuoteDO.setUid(memberVO.getId());
            interlaceEstimateQuoteDO.setInterlaceAccountId(memberVO.getInterlaceAccountId());
            interlaceEstimateQuoteDO.setRate(Convert.toBigDecimal(estimateQuoteResponse.get("rate")));
            interlaceEstimateQuoteDO.setFeeCurrency(Convert.toStr(estimateQuoteResponse.get("feeCurrency")));
            interlaceEstimateQuoteDO.setTtlMs(Convert.toInt(estimateQuoteResponse.get("ttlMs")));
            interlaceEstimateQuoteDO.setQuoteTime(Convert.toLong(estimateQuoteResponse.get("quoteTime")));
            if ("buy".equals(bo.getSide())) {
                if ("USD".equals(bo.getRfqCurrency())) {
                    interlaceEstimateQuoteDO.setFee(fee);
                    interlaceEstimateQuoteDO.setBaseAmount(bo.getRfqAmount().subtract(fee.add(quoteFee)));
                    interlaceEstimateQuoteDO.setQuoteAmount(bo.getRfqAmount());
                    interlaceEstimateQuoteDO.setAdditionalFee(quoteFee);
                } else {
                    fee = fee.setScale(2, RoundingMode.HALF_UP);
                    quoteFee = quoteFee.setScale(2, RoundingMode.HALF_UP);
                    interlaceEstimateQuoteDO.setFee(fee);
                    interlaceEstimateQuoteDO.setBaseAmount(bo.getRfqAmount());
                    interlaceEstimateQuoteDO.setQuoteAmount(bo.getRfqAmount().add(fee.add(quoteFee)));
                    interlaceEstimateQuoteDO.setAdditionalFee(quoteFee);
                }
            }
            if ("sell".equals(bo.getSide())) {
                if ("USD".equals(bo.getRfqCurrency())) {
                    interlaceEstimateQuoteDO.setFee(fee);
                    interlaceEstimateQuoteDO.setBaseAmount(bo.getRfqAmount().add(fee.add(quoteFee)));
                    interlaceEstimateQuoteDO.setQuoteAmount(bo.getRfqAmount());
                    interlaceEstimateQuoteDO.setAdditionalFee(quoteFee);
                } else {
                    fee = fee.setScale(2, RoundingMode.HALF_UP);
                    quoteFee = quoteFee.setScale(2, RoundingMode.HALF_UP);
                    interlaceEstimateQuoteDO.setFee(fee);
                    interlaceEstimateQuoteDO.setBaseAmount(bo.getRfqAmount());
                    interlaceEstimateQuoteDO.setQuoteAmount(bo.getRfqAmount().subtract(fee.add(quoteFee)));
                    interlaceEstimateQuoteDO.setAdditionalFee(quoteFee);
                }
            }
            interlaceEstimateQuoteMapper.insert(interlaceEstimateQuoteDO);
            return interlaceEstimateQuoteDO;
        }
        throw new ServiceException("获取询价信息失败，请稍后再试！");
    }

    @Override
    public String updateFile(UploadFileRequest request) {
        return interlaceService.uploadFile(request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean kyc(InterlaceKycBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        /** 获取账号信息 */
        InterlaceMemberDO member = interlaceMemberMapper.selectById(loginUser.getUserId());
        if (member == null) {
            throw new ServiceException("当前用户不存在！");
        }
        /** 检查国籍二字码 */
        CountryDictDO nationalityDO = countryDictMapper.selectOne(new LambdaQueryWrapper<CountryDictDO>()
            .eq(CountryDictDO::getNationalityCountryCode, bo.getNationality())
            .last("LIMIT 1"));
        if (nationalityDO == null) {
            throw new ServiceException("请选择正确的国籍！");
        }
        /** 检查居住地国家二字码 */
        CountryDictDO countryDO = countryDictMapper.selectOne(new LambdaQueryWrapper<CountryDictDO>()
            .eq(CountryDictDO::getNationalityCountryCode, bo.getCountry())
            .last("LIMIT 1"));
        if (countryDO == null) {
            throw new ServiceException("请选择正确的居住国家！");
        }
        /** 校验 */
        String addressStateName = null;
        if (bo.getNationality().equals("CN")) {
            // 中国大陆
            if (!(bo.getIdType().equals("CN-RIC") || bo.getIdType().equals("PASSPORT"))) {
                throw new ServiceException("请选择正确的证件类型！");
            }
        } else if (bo.getNationality().equals("HK")) {
            // 中国香港
            if (!(bo.getIdType().equals("HK-HKID") || bo.getIdType().equals("PASSPORT"))) {
                throw new ServiceException("请选择正确的证件类型！");
            }
        } else {
            // 其他国家/地区
            if (!(bo.getIdType().equals("DLN") ||
                bo.getIdType().equals("PASSPORT") ||
                bo.getIdType().equals("Government-Issued ID Card"))) {
                throw new ServiceException("请选择正确的证件类型！");
            }
            if (bo.getNationality().equals("US")) {
                // 美国
                if (bo.getSsn() == null || bo.getSsn().equals("")) {
                    throw new ServiceException("请输入正确的 Social Security Number！");
                }
            }
        }
        if (bo.getCountry().equals("US") || bo.getCountry().equals("CA")) {
            StateDictDO stateDictDO = stateDictMapper.selectOne(new LambdaQueryWrapper<StateDictDO>()
                .eq(StateDictDO::getCountryCode, bo.getCountry())
                .eq(StateDictDO::getCode, bo.getState())
                .last("LIMIT 1"));
            if (stateDictDO == null) {
                throw new ServiceException("请选择正确的州/省！");
            }
            addressStateName = stateDictDO.getEnName();
            bo.setState(stateDictDO.getEnName());
        } else {
            if (bo.getState() == null || bo.getState().equals("")) {
                addressStateName = countryDO.getEnName();
                bo.setState(countryDO.getEnName());
            } else {
                addressStateName = bo.getState();
            }
        }
        if (bo.getIdType().equals("DLN") || bo.getIdType().equals("PASSPORT")) {
            bo.setIdBackId(bo.getIdFrontId());
        }
        if (!bo.getPostalCode().matches("^[a-zA-Z0-9]{1,15}$")) {
            throw new ServiceException("邮政编码格式不正确，只能包含字母和数字，长度为1-15位！");
        }
        InterlaceKycDO interlaceKycDO = interlaceKycMapper.selectOne(new LambdaQueryWrapper<InterlaceKycDO>()
            .eq(InterlaceKycDO::getUid, loginUser.getUserId()));
        if (interlaceKycDO != null) {
            if (interlaceKycDO.getStatus().equals("Passed")) {
                throw new ServiceException("当前用户已通过kyc验证！");
            }
            KycRequest request = BeanUtil.toBean(bo, KycRequest.class);
            request.setAddress(BeanUtil.toBean(bo, KycAddressRequest.class));
            request.setSourceType("api");
            BeanUtil.copyProperties(bo, interlaceKycDO);
            interlaceKycDO.setUid(loginUser.getUserId());
            interlaceKycDO.setInterlaceAccountId(member.getInterlaceAccountId());
            interlaceKycDO.setCreateTime(System.currentTimeMillis());
            interlaceKycDO.setUpdateTime(System.currentTimeMillis());
            interlaceKycDO.setNationalityName(nationalityDO.getEnName());
            interlaceKycDO.setAddressCountryName(countryDO.getEnName());
            interlaceKycDO.setAddressStateName(addressStateName);
            interlaceKycDO.setStatus("Request");
            interlaceKycMapper.updateById(interlaceKycDO);
            interlaceService.kyc(request, member.getInterlaceAccountId());
        } else {
            interlaceKycDO = new InterlaceKycDO();
            KycRequest request = BeanUtil.toBean(bo, KycRequest.class);
            request.setSourceType("api");
            KycAddressRequest address = BeanUtil.toBean(bo, KycAddressRequest.class);
            request.setAddress(address);
            BeanUtil.copyProperties(bo, interlaceKycDO);
            interlaceKycDO.setUid(loginUser.getUserId());
            interlaceKycDO.setInterlaceAccountId(member.getInterlaceAccountId());
            interlaceKycDO.setCreateTime(System.currentTimeMillis());
            interlaceKycDO.setUpdateTime(System.currentTimeMillis());
            interlaceKycDO.setNationalityName(nationalityDO.getEnName());
            interlaceKycDO.setAddressCountryName(countryDO.getEnName());
            interlaceKycDO.setAddressStateName(addressStateName);
            interlaceKycDO.setStatus("Request");
            interlaceKycMapper.insert(interlaceKycDO);
            interlaceService.kyc(request, member.getInterlaceAccountId());
        }
        member.setInterlaceAccountKycStatus("Request");
        member.setFirstName(bo.getFirstName());
        member.setLastName(bo.getLastName());
        if ("F".equals(bo.getGender())) {
            member.setSex("1");
        } else if ("M".equals(bo.getGender())) {
            member.setSex("0");
        }
        member.setCountry(bo.getNationality());
        String address = bo.getAddressLine1();
        if (bo.getAddressLine2() != null && !bo.getAddressLine2().equals("")) {
            address += "/" + bo.getAddressLine2();
        }
        member.setAddress(address);
        interlaceMemberMapper.updateById(member);
        return true;
    }

    @Override
    public InterlaceInternalTransferDO internalTransferCrypto(InterlaceInternalTransferBO bo) {
        InternalTransferRequest request = new InternalTransferRequest();
        InternalTransferSourceRequest source = new InternalTransferSourceRequest();
        source.setType(bo.getSourceType());
        source.setCurrency(bo.getSourceCurrency());
        source.setId(bo.getSourceAccountId());
        InternalTransferDestinationRequest destination = new InternalTransferDestinationRequest();
        destination.setType(bo.getDestinationType());
        destination.setCurrency(bo.getDestinationCurrency());
        destination.setId(bo.getDestinationAccountId());
        request.setSource(source);
        request.setDestination(destination);
        request.setAmount(Convert.toStr(bo.getAmount()));
        Map response = interlaceService.internalTransferCrypto(request);
        if (response != null) {
            InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
            interlaceInternalTransferDO.setSourceType(bo.getSourceType());
            interlaceInternalTransferDO.setSourceAccountId(bo.getSourceAccountId());
            interlaceInternalTransferDO.setSourceCurrency(bo.getSourceCurrency());
            interlaceInternalTransferDO.setDestinationType(bo.getDestinationType());
            interlaceInternalTransferDO.setDestinationAccountId(bo.getDestinationAccountId());
            interlaceInternalTransferDO.setDestinationCurrency(bo.getDestinationCurrency());
            interlaceInternalTransferDO.setStatus(Convert.toStr(response.get("status")));
            interlaceInternalTransferDO.setCreateTime(Convert.toLong(response.get("createTime")));
            interlaceInternalTransferDO.setUpdateTime(Convert.toLong(response.get("updateTime")));
            Map amount = (Map) response.get("amount");
            if (amount != null) {
                interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(amount.get("amount")));
                interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(amount.get("currency")));
            }
            Map settled = (Map) response.get("settled");
            if (settled != null) {
                interlaceInternalTransferDO.setSettledAmount(Convert.toBigDecimal(settled.get("amount")));
                interlaceInternalTransferDO.setSettledCurrency(Convert.toStr(settled.get("currency")));
            }
            Map fee = (Map) response.get("settled");
            if (fee != null) {
                interlaceInternalTransferDO.setFeeAmount(Convert.toBigDecimal(fee.get("amount")));
                interlaceInternalTransferDO.setFeeCurrency(Convert.toStr(fee.get("currency")));
            }
            interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
            return interlaceInternalTransferDO;
        }
        throw new ServiceException("资产转移失败，请稍后再试！");
    }

    @Override
    public Map getWallet(String walletId) {
        return this.interlaceService.getWallet(walletId);
    }

    @Override
    public Boolean initialization(String accountId) {
        boolean flag = false;
        try {
            flag = this.interlaceService.initialization(accountId);
        } catch (Exception e) {
            log.error("初始化账户异常{}", e.getMessage());
            if ("Do not repeat initialization".equals(e.getMessage())) {
                flag = true;
            }
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean convertTrades(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        InterlaceEstimateQuoteDO interlaceEstimateQuoteDO = interlaceEstimateQuoteMapper.selectById(id);
        if (interlaceEstimateQuoteDO == null) {
            throw new SecurityException("询价记录不存在！");
        }
        InterlaceBudgetDO budget = interlaceBudgetMapper.selectOne(new LambdaQueryWrapper<InterlaceBudgetDO>()
            .eq(InterlaceBudgetDO::getUid, loginUser.getUserId()));
        if (budget == null) {
            throw new SecurityException("用户未绑定钱包！");
        }
        /** fiat -> crypto */
        if ("buy".equals(interlaceEstimateQuoteDO.getSide())) {
            /** 查询对应的钱包 */
            InterlaceBalancesDO balancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
                .eq(InterlaceBalancesDO::getInterlaceAccountId, interlaceEstimateQuoteDO.getInterlaceAccountId())
                .eq(InterlaceBalancesDO::getWalletType, "Budget")
                .eq(InterlaceBalancesDO::getCurrency, interlaceEstimateQuoteDO.getQuoteCurrency())
                .last("FOR UPDATE"));
            if (balancesDO == null) {
                throw new SecurityException("用户未绑定钱包！");
            }
            if (!interlaceCommunalService.checkBalances(balancesDO, interlaceEstimateQuoteDO.getQuoteAmount())) {
                throw new SecurityException("余额不足！");
            }
            String clientTransactionId = IdempotentKeyGenerator.generateIdempotentKey();
            InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
            interlaceTransfersDO.setUid(loginUser.getUserId());
            interlaceTransfersDO.setScene("buy");
            interlaceTransfersDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
            interlaceTransfersDO.setSourceCurrency(interlaceEstimateQuoteDO.getQuoteCurrency());
            interlaceTransfersDO.setSourceAmount(interlaceEstimateQuoteDO.getQuoteAmount());
            interlaceTransfersDO.setDestinationCurrency(interlaceEstimateQuoteDO.getBaseCurrency());
            interlaceTransfersDO.setDestinationAmount(interlaceEstimateQuoteDO.getBaseAmount());
            interlaceTransfersDO.setRfqCurrency(interlaceEstimateQuoteDO.getRfqCurrency());
            interlaceTransfersDO.setRfqAmount(interlaceEstimateQuoteDO.getRfqAmount());
            interlaceTransfersDO.setRate(Convert.toStr(interlaceEstimateQuoteDO.getRate()));
            interlaceTransfersDO.setStatus("Pending");
            interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
            interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
            interlaceTransfersDO.setTransferId(clientTransactionId);
            interlaceTransfersDO.setSn(SnCreator.generateCTSn());
            interlaceTransfersMapper.insert(interlaceTransfersDO);

            /** 保存对应手续费 */
            List<InterlaceTransfersFeesDO> transfersFeeList = new ArrayList<>();
            InterlaceTransfersFeesDO interlaceTransfersFees1 = new InterlaceTransfersFeesDO();
            interlaceTransfersFees1.setTid(interlaceTransfersDO.getId());
            interlaceTransfersFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
            interlaceTransfersFees1.setAmount(interlaceEstimateQuoteDO.getFee());
            interlaceTransfersFees1.setType("quote");
            transfersFeeList.add(interlaceTransfersFees1);
            InterlaceTransfersFeesDO interlaceTransfersFees2 = new InterlaceTransfersFeesDO();
            interlaceTransfersFees2.setTid(interlaceTransfersDO.getId());
            interlaceTransfersFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
            interlaceTransfersFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
            interlaceTransfersFees2.setType("quote_additional_fee");
            transfersFeeList.add(interlaceTransfersFees2);
            interlaceTransfersFeesMapper.insertBatch(transfersFeeList);

            /** 记录量子账户 */
            InterlaceQuantumTransferDO quantumTransferDO = new InterlaceQuantumTransferDO();
            quantumTransferDO.setUid(loginUser.getUserId());
            quantumTransferDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
            quantumTransferDO.setType("quote_buy");
            quantumTransferDO.setAmount(Convert.toBigDecimal(interlaceEstimateQuoteDO.getQuoteAmount()));
            quantumTransferDO.setTransferObj(interlaceEstimateQuoteDO.getBaseCurrency());
            quantumTransferDO.setTransferId(clientTransactionId);
            quantumTransferDO.setStatus("Pending");
            quantumTransferDO.setCreateTime(System.currentTimeMillis());
            quantumTransferDO.setUpdateTime(System.currentTimeMillis());
            interlaceCommunalService.addQuantumTransfer(quantumTransferDO);

            /** 保存对应手续费 */
            List<InterlaceQuantumTransferFeesDO> feeList = new ArrayList<>();
            InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees1 = new InterlaceQuantumTransferFeesDO();
            interlaceQuantumTransferFees1.setQid(quantumTransferDO.getId());
            interlaceQuantumTransferFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
            interlaceQuantumTransferFees1.setAmount(interlaceEstimateQuoteDO.getFee());
            interlaceQuantumTransferFees1.setType("quote");
            feeList.add(interlaceQuantumTransferFees1);
            InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees2 = new InterlaceQuantumTransferFeesDO();
            interlaceQuantumTransferFees2.setQid(quantumTransferDO.getId());
            interlaceQuantumTransferFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
            interlaceQuantumTransferFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
            interlaceQuantumTransferFees2.setType("quote_additional_fee");
            feeList.add(interlaceQuantumTransferFees2);
            interlaceQuantumTransferFeesMapper.insertBatch(feeList);

            /** 发起预算减少 */
            BudgetChangeRequest budgetChangeRequest = new BudgetChangeRequest();
            budgetChangeRequest.setBudgetId(budget.getRid());
            budgetChangeRequest.setCost(interlaceEstimateQuoteDO.getQuoteAmount());
            budgetChangeRequest.setClientTransactionId(clientTransactionId);
            Boolean budgetBalance = interlaceService.decreaseTheBudgetBalance(budgetChangeRequest);
            if (budgetBalance) {
                /** 更新balance */
                ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                balancesRequest.setAccountId(budget.getAccountId());
                balancesRequest.setLimit("10");
                balancesRequest.setPage("0");
                balancesRequest.setWalletType("Budget");
                interlaceCommunalService.updateBalances(balancesRequest);
            }
        }
        /** crypto -> fiat 2025-11-08 已核对 */
        if ("sell".equals(interlaceEstimateQuoteDO.getSide())) {
            /** 查询对应的钱包 */
            InterlaceBalancesDO balancesDO = interlaceBalancesMapper.selectOne(new LambdaQueryWrapper<InterlaceBalancesDO>()
                .eq(InterlaceBalancesDO::getInterlaceAccountId, interlaceEstimateQuoteDO.getInterlaceAccountId())
                .eq(InterlaceBalancesDO::getWalletType, "CryptoAsset")
                .eq(InterlaceBalancesDO::getCurrency, interlaceEstimateQuoteDO.getBaseCurrency())
                .last("FOR UPDATE"));

            InterlaceBudgetDO interlaceBudgetDO = interlaceBudgetMapper.selectOne(new LambdaQueryWrapper<InterlaceBudgetDO>()
                .eq(InterlaceBudgetDO::getAccountId, interlaceEstimateQuoteDO.getInterlaceAccountId()));
            if (balancesDO == null) {
                throw new SecurityException("用户未绑定加密货币钱包！");
            }
            if (interlaceBudgetDO == null) {
                throw new SecurityException("用户未绑定法定货币钱包！");
            }
            if (!interlaceCommunalService.checkBalances(balancesDO, interlaceEstimateQuoteDO.getBaseAmount())) {
                throw new SecurityException("余额不足！");
            }
            /** 检查主账户余额 */
            MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
                .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
                .eq(MasterBalanceDO::getWalletType, "QuantumAccount")
                .eq(MasterBalanceDO::getCurrency, "USD")
                .last("FOR UPDATE"));
            if (masterBalance == null) {
                throw new SecurityException("暂不支持换汇！");
            }
            if (masterBalance.getAvailable().compareTo(interlaceEstimateQuoteDO.getQuoteAmount()) < 0) {
                /** 表示主量子账户USD的余额低于即将要兑换的金额 */
                this.waitFulfill(interlaceEstimateQuoteDO, loginUser.getUserId());
            } else {
                /** 主量子账户 -> 子量子账户 */
                InterlaceInternalTransferDO transferDO = this.masterAccountToSubAccount(interlaceEstimateQuoteDO.getInterlaceAccountId(), interlaceEstimateQuoteDO.getQuoteAmount());
                if (transferDO != null) {
                    /** 记录提前预支的crypto换汇数量 */
                    MasterBalanceDO masterCryptoBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
                        .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
                        .eq(MasterBalanceDO::getWalletType, "CryptoAsset")
                        .eq(MasterBalanceDO::getCurrency, interlaceEstimateQuoteDO.getBaseCurrency())
                        .last("limit 1 FOR UPDATE"));
                    if (masterCryptoBalance != null) {
                        masterBalanceMapper.increaseWaitQuote(masterCryptoBalance.getId(), interlaceEstimateQuoteDO.getBaseAmount(), System.currentTimeMillis());
                    }
                    /** 保存加密货币交易 */
                    String idempotentKey = IdempotentKeyGenerator.generateIdempotentKey();
                    InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
                    interlaceTransfersDO.setTransferId(idempotentKey);
                    interlaceTransfersDO.setUid(loginUser.getUserId());
                    interlaceTransfersDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
                    interlaceTransfersDO.setScene("sell");
                    interlaceTransfersDO.setSourceCurrency(interlaceEstimateQuoteDO.getBaseCurrency());
                    interlaceTransfersDO.setSourceAmount(interlaceEstimateQuoteDO.getBaseAmount());
                    interlaceTransfersDO.setDestinationCurrency(interlaceEstimateQuoteDO.getQuoteCurrency());
                    interlaceTransfersDO.setDestinationAmount(interlaceEstimateQuoteDO.getQuoteAmount());
                    interlaceTransfersDO.setRfqCurrency(interlaceEstimateQuoteDO.getRfqCurrency());
                    interlaceTransfersDO.setRfqAmount(interlaceEstimateQuoteDO.getRfqAmount());
                    interlaceTransfersDO.setRate(Convert.toStr(interlaceEstimateQuoteDO.getRate()));
                    interlaceTransfersDO.setStatus("Pending");
                    interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
                    interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
                    interlaceTransfersDO.setSn(SnCreator.generateCTSn());
                    interlaceTransfersMapper.insert(interlaceTransfersDO);

                    /** 保存对应手续费 */
                    List<InterlaceTransfersFeesDO> feeList = new ArrayList<>();
                    InterlaceTransfersFeesDO interlaceTransfersFees1 = new InterlaceTransfersFeesDO();
                    interlaceTransfersFees1.setTid(interlaceTransfersDO.getId());
                    interlaceTransfersFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
                    interlaceTransfersFees1.setAmount(interlaceEstimateQuoteDO.getFee());
                    interlaceTransfersFees1.setType("quote");
                    feeList.add(interlaceTransfersFees1);
                    InterlaceTransfersFeesDO interlaceTransfersFees2 = new InterlaceTransfersFeesDO();
                    interlaceTransfersFees2.setTid(interlaceTransfersDO.getId());
                    interlaceTransfersFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
                    interlaceTransfersFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
                    interlaceTransfersFees2.setType("quote_additional_fee");
                    feeList.add(interlaceTransfersFees2);
                    interlaceTransfersFeesMapper.insertBatch(feeList);

                    /** 记录量子账户 */
                    InterlaceQuantumTransferDO quantumTransferDO = new InterlaceQuantumTransferDO();
                    quantumTransferDO.setTransferId(idempotentKey);
                    quantumTransferDO.setUid(loginUser.getUserId());
                    quantumTransferDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
                    quantumTransferDO.setType("quote_sell");
                    quantumTransferDO.setAmount(interlaceEstimateQuoteDO.getQuoteAmount());
                    quantumTransferDO.setTransferObj(interlaceEstimateQuoteDO.getBaseCurrency());
                    quantumTransferDO.setStatus("Pending");
                    quantumTransferDO.setCreateTime(System.currentTimeMillis());
                    quantumTransferDO.setUpdateTime(System.currentTimeMillis());
                    interlaceCommunalService.addQuantumTransfer(quantumTransferDO);

                    /** 保存对应手续费 */
                    List<InterlaceQuantumTransferFeesDO> quantumFeeList = new ArrayList<>();
                    InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees1 = new InterlaceQuantumTransferFeesDO();
                    interlaceQuantumTransferFees1.setQid(quantumTransferDO.getId());
                    interlaceQuantumTransferFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
                    interlaceQuantumTransferFees1.setAmount(interlaceEstimateQuoteDO.getFee());
                    interlaceQuantumTransferFees1.setType("quote");
                    quantumFeeList.add(interlaceQuantumTransferFees1);
                    InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees2 = new InterlaceQuantumTransferFeesDO();
                    interlaceQuantumTransferFees2.setQid(quantumTransferDO.getId());
                    interlaceQuantumTransferFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
                    interlaceQuantumTransferFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
                    interlaceQuantumTransferFees2.setType("quote_additional_fee");
                    quantumFeeList.add(interlaceQuantumTransferFees2);
                    interlaceQuantumTransferFeesMapper.insertBatch(quantumFeeList);

                    /** 发起增加预算 */
                    BudgetChangeRequest request = new BudgetChangeRequest();
                    request.setCost(interlaceEstimateQuoteDO.getQuoteAmount());
                    request.setBudgetId(interlaceBudgetDO.getRid());
                    request.setClientTransactionId(idempotentKey);
                    interlaceService.increaseTheBudgetBalance(request);

                    /** 更新子主加密钱包 */
                    interlaceCommunalService.updateCryptoWallet(interlaceEstimateQuoteDO.getInterlaceAccountId(), interlaceEstimateQuoteDO.getBaseCurrency(), interlaceEstimateQuoteDO.getBaseAmount(), "decrease");
                }
            }
        }
        return true;
    }

    @Override
    public InterlaceInternalTransferDO quantumSubAccountToCryptoAssets(QuantumSubAccountToCryptoAssetsRequest
                                                                           request) {
        Map response = interlaceService.quantumSubAccountToCryptoAssets(request);
        InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
        if (response != null) {
            interlaceInternalTransferDO.setRid(Convert.toStr(response.get("id")));
            interlaceInternalTransferDO.setStatus(Convert.toStr(response.get("status")));
            Map source = (Map) response.get("response");
            if (source != null) {
                interlaceInternalTransferDO.setSourceType(Convert.toStr(source.get("type")));
                interlaceInternalTransferDO.setSourceAccountId(Convert.toStr(source.get("id")));
                interlaceInternalTransferDO.setSourceCurrency(Convert.toStr(source.get("currency")));
            }
            Map destination = (Map) response.get("destination");
            if (destination != null) {
                interlaceInternalTransferDO.setDestinationType(Convert.toStr(destination.get("type")));
                interlaceInternalTransferDO.setDestinationAccountId(Convert.toStr(destination.get("id")));
                interlaceInternalTransferDO.setDestinationCurrency(Convert.toStr(destination.get("currency")));
            }
            Map amount = (Map) response.get("amount");
            if (amount != null) {
                interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(amount.get("amount")));
                interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(amount.get("currency")));
            }
            interlaceInternalTransferDO.setCreateTime(System.currentTimeMillis());
            interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
            interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
        }
        return interlaceInternalTransferDO;
    }

    @Override
    public InterlaceInternalTransferDO cryptoAssetsToQuantumSubAccount(CryptoAssetsToQuantumSubAccountRequest
                                                                           request) {
        Map response = interlaceService.cryptoAssetsToQuantumSubAccount(request);
        InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
        if (response != null) {
            interlaceInternalTransferDO.setRid(Convert.toStr(response.get("id")));
            interlaceInternalTransferDO.setStatus(Convert.toStr(response.get("status")));
            Map source = (Map) response.get("response");
            if (source != null) {
                interlaceInternalTransferDO.setSourceType(Convert.toStr(source.get("type")));
                interlaceInternalTransferDO.setSourceAccountId(Convert.toStr(source.get("id")));
                interlaceInternalTransferDO.setSourceCurrency(Convert.toStr(source.get("currency")));
            }
            Map destination = (Map) response.get("destination");
            if (destination != null) {
                interlaceInternalTransferDO.setDestinationType(Convert.toStr(destination.get("type")));
                interlaceInternalTransferDO.setDestinationAccountId(Convert.toStr(destination.get("id")));
                interlaceInternalTransferDO.setDestinationCurrency(Convert.toStr(destination.get("currency")));
            }
            Map amount = (Map) response.get("amount");
            if (amount != null) {
                interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(amount.get("amount")));
                interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(amount.get("currency")));
            }
            interlaceInternalTransferDO.setCreateTime(System.currentTimeMillis());
            interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
            interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
        }
        return interlaceInternalTransferDO;
    }

    @Override
    public Boolean checkIsKyc() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        boolean flag = false;
        InterlaceKycDO interlaceKycDO = interlaceKycMapper.selectOne(new LambdaQueryWrapper<InterlaceKycDO>().eq(InterlaceKycDO::getUid, loginUser.getUserId()));
        if (interlaceKycDO == null) {
            flag = true;
        } else {
            if ("Pending".equals(interlaceKycDO.getStatus()) || "Request".equals(interlaceKycDO.getStatus()) || "Passed".equals(interlaceKycDO.getStatus())) {
                flag = false;
            } else {
                flag = true;
            }
        }
        return flag;
    }

    @Override
    public InterlaceKycVO apiKycInfo() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        return interlaceKycMapper.selectVoOne(new LambdaQueryWrapper<InterlaceKycDO>()
            .eq(InterlaceKycDO::getUid, loginUser.getUserId()));
    }

    @Override
    public List<InterlaceBlockchainAddressCatalogueVO> blockchainAddressCatalogueList(String currency, String
        chain, String keyword) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<InterlaceBlockchainAddressCatalogueDO> lqw = new LambdaQueryWrapper<InterlaceBlockchainAddressCatalogueDO>();
        lqw.eq(InterlaceBlockchainAddressCatalogueDO::getCurrency, currency)
            .eq(InterlaceBlockchainAddressCatalogueDO::getChain, chain)
            .eq(InterlaceBlockchainAddressCatalogueDO::getUid, loginUser.getUserId())
            .and(StringUtils.isNotBlank(keyword),
                qr -> qr.like(InterlaceBlockchainAddressCatalogueDO::getNickName, keyword).or()
                    .like(InterlaceBlockchainAddressCatalogueDO::getChain, keyword).or()
                    .like(InterlaceBlockchainAddressCatalogueDO::getCurrency, keyword)
            ).orderByAsc(InterlaceBlockchainAddressCatalogueDO::getSort);
        return interlaceBlockchainAddressCatalogueMapper.selectVoList(lqw);
    }

    @Override
    public InterlaceInternalTransferDO cryptoAssetsToMasterWallet(HandleInternalTransferCryptoBO bo) {
        try {
            InterlaceInternalTransferBO sourceToMaster = new InterlaceInternalTransferBO();
            sourceToMaster.setSourceType("crypto_assets");
            sourceToMaster.setSourceAccountId(bo.getSourceAccountId());
            sourceToMaster.setSourceCurrency(bo.getCurrency());
            sourceToMaster.setDestinationType("crypto_assets");
            sourceToMaster.setDestinationAccountId(interlaceConfig.getMasterAccount());
            sourceToMaster.setDestinationCurrency(bo.getCurrency());
            sourceToMaster.setAmount(bo.getAmount());
            InterlaceInternalTransferDO internalTransferDO = this.internalTransferCrypto(sourceToMaster);
            if (internalTransferDO != null) {
                if ("Closed".equals(internalTransferDO.getStatus())) {
                    /** 更新balance */
                    ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                    balancesRequest.setAccountId(interlaceConfig.getMasterAccount());
                    balancesRequest.setLimit("50");
                    balancesRequest.setPage("0");
                    balancesRequest.setWalletType("CryptoAsset");
                    interlaceCommunalService.updateMasterBalances(balancesRequest);
                }
            }
            return internalTransferDO;
        } catch (Exception e) {
            log.error("子加密货币账户->主加密账户转移失败，accountId账户{},错误信息{}", bo.getSourceAccountId(), e.getMessage());
        }
        return null;
    }

    @Override
    public InterlaceInternalTransferDO masterWalletToCryptoAssets(HandleInternalTransferCryptoBO bo) {
        try {
            InterlaceInternalTransferBO sourceToMaster = new InterlaceInternalTransferBO();
            sourceToMaster.setSourceType("crypto_assets");
            sourceToMaster.setSourceAccountId(interlaceConfig.getMasterAccount());
            sourceToMaster.setSourceCurrency(bo.getCurrency());
            sourceToMaster.setDestinationType("crypto_assets");
            sourceToMaster.setDestinationAccountId(bo.getDestinationAccountId());
            sourceToMaster.setDestinationCurrency(bo.getCurrency());
            sourceToMaster.setAmount(bo.getAmount());
            InterlaceInternalTransferDO internalTransferDO = this.internalTransferCrypto(sourceToMaster);
            if (internalTransferDO != null) {
                if ("Closed".equals(internalTransferDO.getStatus())) {
                    /** 更新balance */
                    ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                    balancesRequest.setAccountId(interlaceConfig.getMasterAccount());
                    balancesRequest.setLimit("50");
                    balancesRequest.setPage("0");
                    balancesRequest.setWalletType("CryptoAsset");
                    interlaceCommunalService.updateMasterBalances(balancesRequest);
                }
            }
            return internalTransferDO;
        } catch (Exception e) {
            log.error("主加密账户转移->子加密货币账户失败，accountId账户{},错误信息{}", bo.getDestinationAccountId(), e.getMessage());
        }
        return null;
    }

    @Override
    public InterlaceInternalTransferDO subAccountToMasterAccount(String subAccountId, BigDecimal amount) {
        try {
            amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
            SubAccountToMasterAccountRequest request = new SubAccountToMasterAccountRequest();
            request.setAmount(Convert.toStr(amount));
            InfinitySubAccountRequest source = new InfinitySubAccountRequest();
            source.setId(subAccountId);
            source.setType("quantum_sub_account");
            request.setSource(source);
            InfinityAccountRequest destination = new InfinityAccountRequest();
            destination.setType("quantum_account");
            request.setDestination(destination);
            Map response = interlaceService.subAccountToMasterAccount(request);
            InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
            if (response != null) {
                String status = Convert.toStr(response.get("status"));
                interlaceInternalTransferDO.setRid(Convert.toStr(response.get("id")));
                interlaceInternalTransferDO.setStatus(status);
                Map responseSource = (Map) response.get("response");
                if (responseSource != null) {
                    interlaceInternalTransferDO.setSourceType(Convert.toStr(responseSource.get("type")));
                    interlaceInternalTransferDO.setSourceAccountId(Convert.toStr(responseSource.get("id")));
                    interlaceInternalTransferDO.setSourceCurrency(Convert.toStr(responseSource.get("currency")));
                }
                Map responseDestination = (Map) response.get("destination");
                if (responseDestination != null) {
                    interlaceInternalTransferDO.setDestinationType(Convert.toStr(responseDestination.get("type")));
                    interlaceInternalTransferDO.setDestinationAccountId(Convert.toStr(responseDestination.get("id")));
                    interlaceInternalTransferDO.setDestinationCurrency(Convert.toStr(responseDestination.get("currency")));
                }
                Map responseAmount = (Map) response.get("amount");
                if (responseAmount != null) {
                    interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(responseAmount.get("amount")));
                    interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(responseAmount.get("currency")));
                }
                Map responseSettled = (Map) response.get("settled");
                if (responseSettled != null) {
                    interlaceInternalTransferDO.setSettledAmount(Convert.toBigDecimal(responseSettled.get("amount")));
                    interlaceInternalTransferDO.setSettledCurrency(Convert.toStr(responseSettled.get("currency")));
                }
                Map responseFee = (Map) response.get("fee");
                if (responseFee != null) {
                    interlaceInternalTransferDO.setFeeAmount(Convert.toBigDecimal(responseFee.get("amount")));
                    interlaceInternalTransferDO.setFeeCurrency(Convert.toStr(responseFee.get("currency")));
                }
                interlaceInternalTransferDO.setCreateTime(System.currentTimeMillis());
                interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
                interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
                /** 更新balance */
                ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                balancesRequest.setAccountId(interlaceConfig.getMasterAccount());
                balancesRequest.setLimit("50");
                balancesRequest.setPage("0");
                balancesRequest.setWalletType("QuantumAccount");
                interlaceCommunalService.updateMasterBalances(balancesRequest);
                return interlaceInternalTransferDO;
            }
        } catch (Exception e) {
            log.error("子量子账户->主量子账户失败，accountId账户{},错误信息{}", subAccountId, e.getMessage());
        }
        return null;
    }

    @Override
    public InterlaceInternalTransferDO masterAccountToSubAccount(String subAccountId, BigDecimal amount) {
        try {
            amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
            MasterAccountToSubAccountRequest request = new MasterAccountToSubAccountRequest();
            request.setAmount(Convert.toStr(amount));
            InfinityAccountRequest source = new InfinityAccountRequest();
            source.setType("quantum_account");
            request.setSource(source);
            InfinitySubAccountRequest destination = new InfinitySubAccountRequest();
            destination.setType("quantum_sub_account");
            destination.setId(subAccountId);
            request.setDestination(destination);
            Map response = interlaceService.masterAccountToSubAccount(request);
            InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
            if (response != null) {
                String status = Convert.toStr(response.get("status"));
                interlaceInternalTransferDO.setRid(Convert.toStr(response.get("id")));
                interlaceInternalTransferDO.setStatus(status);
                Map responseSource = (Map) response.get("response");
                if (responseSource != null) {
                    interlaceInternalTransferDO.setSourceType(Convert.toStr(responseSource.get("type")));
                    interlaceInternalTransferDO.setSourceAccountId(Convert.toStr(responseSource.get("id")));
                    interlaceInternalTransferDO.setSourceCurrency(Convert.toStr(responseSource.get("currency")));
                }
                Map responseDestination = (Map) response.get("destination");
                if (responseDestination != null) {
                    interlaceInternalTransferDO.setDestinationType(Convert.toStr(responseDestination.get("type")));
                    interlaceInternalTransferDO.setDestinationAccountId(Convert.toStr(responseDestination.get("id")));
                    interlaceInternalTransferDO.setDestinationCurrency(Convert.toStr(responseDestination.get("currency")));
                }
                Map responseAmount = (Map) response.get("amount");
                if (responseAmount != null) {
                    interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(responseAmount.get("amount")));
                    interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(responseAmount.get("currency")));
                }
                Map responseSettled = (Map) response.get("settled");
                if (responseSettled != null) {
                    interlaceInternalTransferDO.setSettledAmount(Convert.toBigDecimal(responseSettled.get("amount")));
                    interlaceInternalTransferDO.setSettledCurrency(Convert.toStr(responseSettled.get("currency")));
                }
                Map responseFee = (Map) response.get("fee");
                if (responseFee != null) {
                    interlaceInternalTransferDO.setFeeAmount(Convert.toBigDecimal(responseFee.get("amount")));
                    interlaceInternalTransferDO.setFeeCurrency(Convert.toStr(responseFee.get("currency")));
                }
                interlaceInternalTransferDO.setCreateTime(System.currentTimeMillis());
                interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
                interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
                /** 更新balance */
                ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                balancesRequest.setAccountId(interlaceConfig.getMasterAccount());
                balancesRequest.setLimit("50");
                balancesRequest.setPage("0");
                balancesRequest.setWalletType("QuantumAccount");
                interlaceCommunalService.updateMasterBalances(balancesRequest);
                return interlaceInternalTransferDO;
            }
        } catch (Exception e) {
            log.error("主量子账户->子量子账户失败，accountId账户{},错误信息{}", subAccountId, e.getMessage());
        }
        return null;
    }

    @Override
    public TableDataInfo<CustomInterlaceQuantumTransferVO> internalQuantumTransferPageList(String type, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }

        LambdaQueryWrapper<InterlaceQuantumTransferDO> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InterlaceQuantumTransferDO::getUid, loginUser.getUserId());
        if ("quote".equals(type)) {
            lqw.in(InterlaceQuantumTransferDO::getType, "quote_buy", "quote_sell");
        } else {
            lqw.notIn(InterlaceQuantumTransferDO::getType, "quote_buy", "quote_sell");
        }
        lqw.orderByDesc(InterlaceQuantumTransferDO::getCreateTime);
        Page<InterlaceQuantumTransferVO> result = interlaceQuantumTransferMapper.selectVoPage(pageQuery.build(), lqw);
        Page<CustomInterlaceQuantumTransferVO> customResult = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
        List<CustomInterlaceQuantumTransferVO> customRecords = result.getRecords().stream()
            .map(record -> {
                CustomInterlaceQuantumTransferVO customVO = new CustomInterlaceQuantumTransferVO();
                BeanUtil.copyProperties(record, customVO);
                List<InterlaceQuantumTransferFeesVO> feesVOS = interlaceQuantumTransferFeesMapper.selectVoList(new LambdaQueryWrapper<InterlaceQuantumTransferFeesDO>()
                    .eq(InterlaceQuantumTransferFeesDO::getQid, record.getId()));
                customVO.setFees(feesVOS);
                return customVO;
            })
            .collect(Collectors.toList());
        customResult.setRecords(customRecords);
        return TableDataInfo.build(customResult);
    }

    @Override
    public TableDataInfo<InterlaceTransfersVO> internalCryptoTransferPageList(String currency, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<InterlaceTransfersDO> lqw = new LambdaQueryWrapper<InterlaceTransfersDO>();
        lqw.eq(InterlaceTransfersDO::getUid, loginUser.getUserId())
            .and(wrapper -> wrapper
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "crypto_assets_in")
                    .eq(InterlaceTransfersDO::getDestinationCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "crypto_assets_out")
                    .eq(InterlaceTransfersDO::getSourceCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "assets_withdrawal")
                    .eq(InterlaceTransfersDO::getSourceCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "assets_deposit")
                    .eq(InterlaceTransfersDO::getDestinationCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "assets_deposit")
                    .eq(InterlaceTransfersDO::getDestinationCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "buy")
                    .eq(InterlaceTransfersDO::getDestinationCurrency, currency))
                .or(w -> w.eq(InterlaceTransfersDO::getScene, "sell")
                    .eq(InterlaceTransfersDO::getSourceCurrency, currency)))
            .orderByDesc(InterlaceTransfersDO::getUpdateTime);
        Page<InterlaceTransfersVO> result = interlaceTransfersMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public CustomInterlaceQuantumTransferVO internalQuantumTransferDetail(Long id) {
        CustomInterlaceQuantumTransferVO vo = new CustomInterlaceQuantumTransferVO();
        InterlaceQuantumTransferVO transferVO = interlaceQuantumTransferMapper.selectVoById(id);
        if (transferVO != null) {
            BeanUtil.copyProperties(transferVO, vo);
        }
        List<InterlaceQuantumTransferFeesVO> feesVOS = interlaceQuantumTransferFeesMapper.selectVoList(new LambdaQueryWrapper<InterlaceQuantumTransferFeesDO>()
            .eq(InterlaceQuantumTransferFeesDO::getQid, id));
        vo.setFees(feesVOS);
        return vo;
    }

    @Override
    public CustomInterlaceTransfersVO internalCryptoTransferDetail(Long id) {
        CustomInterlaceTransfersVO vo = new CustomInterlaceTransfersVO();
        InterlaceTransfersVO transferVO = interlaceTransfersMapper.selectVoById(id);
        if (transferVO != null) {
            BeanUtil.copyProperties(transferVO, vo);
        }
        List<InterlaceTransfersFeesVO> feesVOS = interlaceTransfersFeesMapper.selectVoList(new LambdaQueryWrapper<InterlaceTransfersFeesDO>()
            .eq(InterlaceTransfersFeesDO::getTid, id));
        vo.setFees(feesVOS);
        return vo;
    }

    /**
     * 定时任务-处理内部转移记录（每隔25秒执行）
     */
    @Scheduled(cron = "0/25 * * * * ?")
    public void handleAffairStart() {
        List<InterlaceInternalTransferDO> list = interlaceInternalTransferMapper.selectList(new LambdaQueryWrapper<InterlaceInternalTransferDO>()
            .eq(InterlaceInternalTransferDO::getStatus, "Pending"));
        if (list != null && list.size() > 0) {
            for (InterlaceInternalTransferDO interlaceInternalTransferDO : list) {
                Map transferResponse = interlaceService.getOnceTransfer(interlaceInternalTransferDO.getRid());
                if (transferResponse != null) {
                    String transferStatus = Convert.toStr(transferResponse.get("status"));
                    if (!transferStatus.equals(interlaceInternalTransferDO.getStatus())) {
                        interlaceInternalTransferDO.setStatus(transferStatus);
                        interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
                        Map settled = (Map) transferResponse.get("settled");
                        if (settled != null) {
                            interlaceInternalTransferDO.setSettledAmount(Convert.toBigDecimal(settled.get("amount")));
                            interlaceInternalTransferDO.setSettledCurrency(Convert.toStr(settled.get("currency")));
                        }
                        Map fee = (Map) transferResponse.get("fee");
                        if (fee != null) {
                            interlaceInternalTransferDO.setFeeAmount(Convert.toBigDecimal(fee.get("amount")));
                            interlaceInternalTransferDO.setFeeCurrency(Convert.toStr(fee.get("currency")));
                        }
                    }
                    interlaceInternalTransferMapper.updateById(interlaceInternalTransferDO);
                    /** 更新主账户的balance */
                    ListAllBalancesRequest balancesRequest = new ListAllBalancesRequest();
                    balancesRequest.setAccountId(interlaceConfig.getMasterAccount());
                    balancesRequest.setLimit("50");
                    balancesRequest.setPage("0");
                    balancesRequest.setWalletType("QuantumAccount");
                    interlaceCommunalService.updateMasterBalances(balancesRequest);
                }
            }
        }
    }

    /**
     * 定时任务-处理等待换汇的记录（每隔35秒执行）
     */
    @Scheduled(cron = "0/35 * * * * ?")
    public void handleWaitFulfill() {
        List<InterlaceTransfersDO> list = interlaceTransfersMapper.selectList(new LambdaQueryWrapper<InterlaceTransfersDO>()
            .eq(InterlaceTransfersDO::getStatus, "Pending")
            .eq(InterlaceTransfersDO::getWaitFulfill, "1"));
        if (list != null && list.size() > 0) {
            for (InterlaceTransfersDO interlaceTransfersDO : list) {
                /** 检查主账户余额 */
                MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
                    .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
                    .eq(MasterBalanceDO::getWalletType, "QuantumAccount")
                    .eq(MasterBalanceDO::getCurrency, "USD")
                    .last("FOR UPDATE"));
                if (masterBalance != null && masterBalance.getAvailable().compareTo(interlaceTransfersDO.getDestinationAmount()) >= 0) {
                    try {
                        /** 主量子账户->子量子账户 （返回状态：Closed）*/
                        InterlaceInternalTransferDO transferDO = this.masterAccountToSubAccount(interlaceTransfersDO.getAccountId(), interlaceTransfersDO.getDestinationAmount());
                        if (transferDO != null && transferDO.getStatus().equals("Closed")) {
                            String idempotentKey = IdempotentKeyGenerator.generateIdempotentKey();
                            String oldTransferId = interlaceTransfersDO.getTransferId();
                            interlaceTransfersDO.setWaitFulfill("0");
                            interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
                            interlaceTransfersDO.setTransferId(idempotentKey);
                            interlaceTransfersMapper.updateById(interlaceTransfersDO);

                            interlaceQuantumTransferMapper.update(null, new LambdaUpdateWrapper<InterlaceQuantumTransferDO>()
                                .set(InterlaceQuantumTransferDO::getTransferId, idempotentKey)
                                .set(InterlaceQuantumTransferDO::getUpdateTime, System.currentTimeMillis())
                                .eq(InterlaceQuantumTransferDO::getTransferId, oldTransferId)
                                .eq(InterlaceQuantumTransferDO::getStatus, "Pending"));

                            /** 发起增加预算 */
                            InterlaceBudgetDO interlaceBudgetDO = interlaceBudgetMapper.selectOne(new LambdaQueryWrapper<InterlaceBudgetDO>()
                                .eq(InterlaceBudgetDO::getAccountId, interlaceTransfersDO.getAccountId()));
                            if (interlaceBudgetDO != null) {
                                BudgetChangeRequest request = new BudgetChangeRequest();
                                request.setCost(interlaceTransfersDO.getDestinationAmount());
                                request.setBudgetId(interlaceBudgetDO.getRid());
                                request.setClientTransactionId(idempotentKey);
                                interlaceService.increaseTheBudgetBalance(request);
                            }
                        }
                    } catch (Exception e) {
                        log.error("处理等待换汇的记录操作失败 =》{}", e.getMessage());
                    }
                }
            }
        }
    }

    /**
     * 定时任务-处理换汇（每隔55秒执行）
     */
    @Scheduled(cron = "0/55 * * * * ?")
    public void handleQuoteUSDT() {
        Integer threshold = 50;
        InterlaceWarningVO quoteUSDT = interlaceWarningMapper.selectVoOne(new LambdaQueryWrapper<InterlaceWarningDO>()
            .eq(InterlaceWarningDO::getType, "QuoteUSDT")
            .last("limit 1"));
        if (quoteUSDT != null) {
            threshold = quoteUSDT.getThreshold();
        }
        BigDecimal quoteAmount = BigDecimal.valueOf(threshold);
        MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
            .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
            .eq(MasterBalanceDO::getWalletType, "CryptoAsset")
            .eq(MasterBalanceDO::getCurrency, "USDT")
            .last("limit 1 FOR UPDATE"));
        if (masterBalance != null && masterBalance.getWaitQuote().compareTo(quoteAmount) == 1) {
            String idempotentKey = IdempotentKeyGenerator.generateIdempotentKey();
            ConvertTradesRequest request = new ConvertTradesRequest();
            request.setIdempotencyKey(idempotentKey);
            request.setAccountId(interlaceConfig.getMasterAccount());
            request.setBaseCurrency("USDT");
            request.setQuoteCurrency("USD");
            request.setSide("sell");
            request.setRfqCurrency("USD");
            request.setRfqAmount(quoteAmount.toString());
            /** 发起换汇 */
            Map map = interlaceService.convertTrades(request);
            if (map != null) {
                /** 更新待换汇金额 */
                MasterBalanceDO masterBalanceDO = masterBalanceMapper.selectOne(
                    new LambdaQueryWrapper<MasterBalanceDO>()
                        .eq(MasterBalanceDO::getId, masterBalance.getId())
                        .last("FOR UPDATE"));
                if (masterBalanceDO != null) {
                    masterBalanceMapper.decreaseWaitQuote(masterBalanceDO.getId(), quoteAmount, System.currentTimeMillis());
                }
                InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
                interlaceTransfersDO.setUid(interlaceConfig.getMasterMemberId());
                interlaceTransfersDO.setScene("sell");
                interlaceTransfersDO.setAccountId(interlaceConfig.getMasterAccount());
                interlaceTransfersDO.setSourceCurrency("USDT");
                interlaceTransfersDO.setSourceAmount(Convert.toBigDecimal(map.get("baseAmount")));
                interlaceTransfersDO.setDestinationCurrency("USD");
                interlaceTransfersDO.setDestinationAmount(Convert.toBigDecimal(map.get("quoteAmount")));
                interlaceTransfersDO.setRfqCurrency("USD");
                interlaceTransfersDO.setRfqAmount(quoteAmount);
                interlaceTransfersDO.setRate(Convert.toStr(map.get("rate")));
                interlaceTransfersDO.setStatus("Closed");
                interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
                interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
                interlaceTransfersDO.setTransferId(idempotentKey);
                interlaceTransfersDO.setSn(SnCreator.generateCTSn());
                interlaceTransfersMapper.insert(interlaceTransfersDO);
                InterlaceTransfersFeesDO interlaceTransfersItemDO = new InterlaceTransfersFeesDO();
                interlaceTransfersItemDO.setTid(interlaceTransfersDO.getId());
                interlaceTransfersItemDO.setCurrency(Convert.toStr(map.get("feeCurrency")));
                interlaceTransfersItemDO.setAmount(Convert.toBigDecimal(map.get("fee")));
                interlaceTransfersItemDO.setCreateTime(System.currentTimeMillis());
                interlaceTransfersItemDO.setType("quote");
                interlaceTransfersFeesMapper.insert(interlaceTransfersItemDO);
                /** 总换汇账户 转移到 总量子账户（返回：Pending状态） */
                this.cryptoAssetsToMasterWallet(quoteAmount);
            }
        }
    }

    /**
     * 定时任务-处理换汇（每隔57秒执行）
     */
    @Scheduled(cron = "0/57 * * * * ?")
    public void handleQuoteUSDC() {
        Integer threshold = 50;
        InterlaceWarningVO quoteUSDT = interlaceWarningMapper.selectVoOne(new LambdaQueryWrapper<InterlaceWarningDO>()
            .eq(InterlaceWarningDO::getType, "QuoteUSDC")
            .last("limit 1"));
        if (quoteUSDT != null) {
            threshold = quoteUSDT.getThreshold();
        }
        BigDecimal quoteAmount = BigDecimal.valueOf(threshold);
        MasterBalanceDO masterBalance = masterBalanceMapper.selectOne(new LambdaQueryWrapper<MasterBalanceDO>()
            .eq(MasterBalanceDO::getAccountId, interlaceConfig.getMasterAccount())
            .eq(MasterBalanceDO::getWalletType, "CryptoAsset")
            .eq(MasterBalanceDO::getCurrency, "USDC")
            .last("limit 1 FOR UPDATE"));
        if (masterBalance != null && masterBalance.getWaitQuote().compareTo(quoteAmount) == 1) {
            String idempotentKey = IdempotentKeyGenerator.generateIdempotentKey();
            ConvertTradesRequest request = new ConvertTradesRequest();
            request.setIdempotencyKey(idempotentKey);
            request.setAccountId(interlaceConfig.getMasterAccount());
            request.setBaseCurrency("USDC");
            request.setQuoteCurrency("USD");
            request.setSide("sell");
            request.setRfqCurrency("USD");
            request.setRfqAmount(quoteAmount.toString());
            /** 发起换汇 */
            Map map = interlaceService.convertTrades(request);
            if (map != null) {
                /** 更新待换汇金额 */
                MasterBalanceDO masterBalanceDO = masterBalanceMapper.selectOne(
                    new LambdaQueryWrapper<MasterBalanceDO>()
                        .eq(MasterBalanceDO::getId, masterBalance.getId())
                        .last("FOR UPDATE"));
                if (masterBalanceDO != null) {
                    masterBalanceMapper.decreaseWaitQuote(masterBalanceDO.getId(), quoteAmount, System.currentTimeMillis());
                }

                InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
                interlaceTransfersDO.setUid(interlaceConfig.getMasterMemberId());
                interlaceTransfersDO.setScene("sell");
                interlaceTransfersDO.setAccountId(interlaceConfig.getMasterAccount());
                interlaceTransfersDO.setSourceCurrency("USDC");
                interlaceTransfersDO.setSourceAmount(Convert.toBigDecimal(map.get("baseAmount")));
                interlaceTransfersDO.setDestinationCurrency("USD");
                interlaceTransfersDO.setDestinationAmount(Convert.toBigDecimal(map.get("quoteAmount")));
                interlaceTransfersDO.setRfqCurrency("USD");
                interlaceTransfersDO.setRfqAmount(quoteAmount);
                interlaceTransfersDO.setRate(Convert.toStr(map.get("rate")));
                interlaceTransfersDO.setStatus("Closed");
                interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
                interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
                interlaceTransfersDO.setTransferId(idempotentKey);
                interlaceTransfersDO.setSn(SnCreator.generateCTSn());
                interlaceTransfersMapper.insert(interlaceTransfersDO);
                InterlaceTransfersFeesDO interlaceTransfersItemDO = new InterlaceTransfersFeesDO();
                interlaceTransfersItemDO.setTid(interlaceTransfersDO.getId());
                interlaceTransfersItemDO.setCurrency(Convert.toStr(map.get("feeCurrency")));
                interlaceTransfersItemDO.setAmount(Convert.toBigDecimal(map.get("fee")));
                interlaceTransfersItemDO.setCreateTime(System.currentTimeMillis());
                interlaceTransfersItemDO.setType("quote");
                interlaceTransfersFeesMapper.insert(interlaceTransfersItemDO);
                /** 总换汇账户 转移到 总量子账户（返回：Pending状态） */
                this.cryptoAssetsToMasterWallet(quoteAmount);
            }
        }
    }

    /**
     * 总量子账户USD余额不足，发起换汇
     */
    public void waitFulfill(InterlaceEstimateQuoteDO interlaceEstimateQuoteDO, Long userId) {
        String idempotentKey = IdempotentKeyGenerator.generateIdempotentKey();
        ConvertTradesRequest request = new ConvertTradesRequest();
        request.setIdempotencyKey(idempotentKey);
        request.setAccountId(interlaceConfig.getMasterAccount());
        request.setBaseCurrency(interlaceEstimateQuoteDO.getBaseCurrency());
        request.setQuoteCurrency("USD");
        request.setSide("sell");
        request.setRfqCurrency("USD");
        request.setRfqAmount(Convert.toStr(interlaceEstimateQuoteDO.getQuoteAmount()));
        /** 发起换汇 */
        String transferId = IdempotentKeyGenerator.generateIdempotentKey();
        Map map = interlaceService.convertTrades(request);
        if (map != null) {
            InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
            interlaceTransfersDO.setUid(interlaceConfig.getMasterMemberId());
            interlaceTransfersDO.setScene("sell");
            interlaceTransfersDO.setAccountId(interlaceConfig.getMasterAccount());
            interlaceTransfersDO.setSourceCurrency(interlaceEstimateQuoteDO.getBaseCurrency());
            interlaceTransfersDO.setSourceAmount(Convert.toBigDecimal(map.get("baseAmount")));
            interlaceTransfersDO.setDestinationCurrency("USD");
            interlaceTransfersDO.setDestinationAmount(Convert.toBigDecimal(map.get("quoteAmount")));
            interlaceTransfersDO.setRfqCurrency("USD");
            interlaceTransfersDO.setRfqAmount(interlaceEstimateQuoteDO.getQuoteAmount());
            interlaceTransfersDO.setRate(Convert.toStr(map.get("rate")));
            interlaceTransfersDO.setStatus("Closed");
            interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
            interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
            interlaceTransfersDO.setTransferId(idempotentKey);
            interlaceTransfersDO.setSn(SnCreator.generateCTSn());
            interlaceTransfersMapper.insert(interlaceTransfersDO);
            InterlaceTransfersFeesDO interlaceTransfersItemDO = new InterlaceTransfersFeesDO();
            interlaceTransfersItemDO.setTid(interlaceTransfersDO.getId());
            interlaceTransfersItemDO.setCurrency(Convert.toStr(map.get("feeCurrency")));
            interlaceTransfersItemDO.setAmount(Convert.toBigDecimal(map.get("fee")));
            interlaceTransfersItemDO.setCreateTime(System.currentTimeMillis());
            interlaceTransfersItemDO.setType("quote");
            interlaceTransfersFeesMapper.insert(interlaceTransfersItemDO);
            /** 总换汇账户 转移到 总量子账户（返回：Pending状态） */
            this.cryptoAssetsToMasterWallet(interlaceEstimateQuoteDO.getQuoteAmount());
        }

        /** 保存用户账户的加密货币交易记录 */
        InterlaceTransfersDO interlaceTransfersDO = new InterlaceTransfersDO();
        interlaceTransfersDO.setTransferId(transferId);
        interlaceTransfersDO.setUid(userId);
        interlaceTransfersDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
        interlaceTransfersDO.setScene("sell");
        interlaceTransfersDO.setSourceCurrency(interlaceEstimateQuoteDO.getBaseCurrency());
        interlaceTransfersDO.setSourceAmount(interlaceEstimateQuoteDO.getBaseAmount());
        interlaceTransfersDO.setDestinationCurrency(interlaceEstimateQuoteDO.getQuoteCurrency());
        interlaceTransfersDO.setDestinationAmount(interlaceEstimateQuoteDO.getQuoteAmount());
        interlaceTransfersDO.setRfqCurrency(interlaceEstimateQuoteDO.getRfqCurrency());
        interlaceTransfersDO.setRfqAmount(interlaceEstimateQuoteDO.getRfqAmount());
        interlaceTransfersDO.setRate(Convert.toStr(interlaceEstimateQuoteDO.getRate()));
        interlaceTransfersDO.setStatus("Pending");
        interlaceTransfersDO.setCreateTime(System.currentTimeMillis());
        interlaceTransfersDO.setUpdateTime(System.currentTimeMillis());
        interlaceTransfersDO.setSn(SnCreator.generateCTSn());
        interlaceTransfersDO.setWaitFulfill("1");
        interlaceTransfersMapper.insert(interlaceTransfersDO);
        /** 保存对应手续费 */
        List<InterlaceTransfersFeesDO> feeList = new ArrayList<>();
        InterlaceTransfersFeesDO interlaceTransfersFees1 = new InterlaceTransfersFeesDO();
        interlaceTransfersFees1.setTid(interlaceTransfersDO.getId());
        interlaceTransfersFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
        interlaceTransfersFees1.setAmount(interlaceEstimateQuoteDO.getFee());
        interlaceTransfersFees1.setType("quote");
        feeList.add(interlaceTransfersFees1);
        InterlaceTransfersFeesDO interlaceTransfersFees2 = new InterlaceTransfersFeesDO();
        interlaceTransfersFees2.setTid(interlaceTransfersDO.getId());
        interlaceTransfersFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
        interlaceTransfersFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
        interlaceTransfersFees2.setType("quote_additional_fee");
        feeList.add(interlaceTransfersFees2);
        interlaceTransfersFeesMapper.insertBatch(feeList);

        /** 记录量子账户 */
        InterlaceQuantumTransferDO quantumTransferDO = new InterlaceQuantumTransferDO();
        quantumTransferDO.setTransferId(transferId);
        quantumTransferDO.setUid(userId);
        quantumTransferDO.setAccountId(interlaceEstimateQuoteDO.getInterlaceAccountId());
        quantumTransferDO.setType("quote_sell");
        quantumTransferDO.setAmount(interlaceEstimateQuoteDO.getQuoteAmount());
        quantumTransferDO.setTransferObj(interlaceEstimateQuoteDO.getBaseCurrency());
        quantumTransferDO.setStatus("Pending");
        quantumTransferDO.setCreateTime(System.currentTimeMillis());
        quantumTransferDO.setUpdateTime(System.currentTimeMillis());
        interlaceCommunalService.addQuantumTransfer(quantumTransferDO);

        /** 保存对应手续费 */
        List<InterlaceQuantumTransferFeesDO> quantumFeeList = new ArrayList<>();
        InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees1 = new InterlaceQuantumTransferFeesDO();
        interlaceQuantumTransferFees1.setQid(quantumTransferDO.getId());
        interlaceQuantumTransferFees1.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
        interlaceQuantumTransferFees1.setAmount(interlaceEstimateQuoteDO.getFee());
        interlaceQuantumTransferFees1.setType("quote");
        quantumFeeList.add(interlaceQuantumTransferFees1);
        InterlaceQuantumTransferFeesDO interlaceQuantumTransferFees2 = new InterlaceQuantumTransferFeesDO();
        interlaceQuantumTransferFees2.setQid(quantumTransferDO.getId());
        interlaceQuantumTransferFees2.setCurrency(interlaceEstimateQuoteDO.getFeeCurrency());
        interlaceQuantumTransferFees2.setAmount(interlaceEstimateQuoteDO.getAdditionalFee());
        interlaceQuantumTransferFees2.setType("quote_additional_fee");
        quantumFeeList.add(interlaceQuantumTransferFees2);
        interlaceQuantumTransferFeesMapper.insertBatch(quantumFeeList);

        /** 更新子主加密钱包 */
        interlaceCommunalService.updateCryptoWallet(interlaceEstimateQuoteDO.getInterlaceAccountId(), interlaceEstimateQuoteDO.getBaseCurrency(), interlaceEstimateQuoteDO.getBaseAmount(), "decrease");
    }

    /**
     * 总换汇账户 到 中量子账户
     */
    public void cryptoAssetsToMasterWallet(BigDecimal quoteAmount) {
        CryptoToMasterQuantumRequest transferRequest = new CryptoToMasterQuantumRequest();
        CryptoAssetsRequest source = new CryptoAssetsRequest();
        source.setId(interlaceConfig.getMasterAccount());
        source.setCurrency("USD");
        source.setType("crypto_assets");
        InfinityAccountRequest destination = new InfinityAccountRequest();
        destination.setType("quantum_account");
        transferRequest.setSource(source);
        transferRequest.setDestination(destination);
        transferRequest.setAmount(Convert.toStr(quoteAmount));
        Map response = interlaceService.cryptoToMasterQuantum(transferRequest);
        if (response != null) {
            InterlaceInternalTransferDO interlaceInternalTransferDO = new InterlaceInternalTransferDO();
            interlaceInternalTransferDO.setRid(Convert.toStr(response.get("id")));
            interlaceInternalTransferDO.setSourceType("crypto_assets");
            interlaceInternalTransferDO.setSourceAccountId(interlaceConfig.getMasterAccount());
            interlaceInternalTransferDO.setSourceCurrency("USD");
            interlaceInternalTransferDO.setDestinationType("quantum_sub_account");
            interlaceInternalTransferDO.setDestinationAccountId(interlaceConfig.getMasterAccount());
            interlaceInternalTransferDO.setDestinationCurrency("USD");
            interlaceInternalTransferDO.setStatus(Convert.toStr(response.get("status")));
            interlaceInternalTransferDO.setCreateTime(System.currentTimeMillis());
            interlaceInternalTransferDO.setUpdateTime(System.currentTimeMillis());
            Map amount = (Map) response.get("amount");
            if (amount != null) {
                interlaceInternalTransferDO.setAmountAmount(Convert.toBigDecimal(amount.get("amount")));
                interlaceInternalTransferDO.setAmountCurrency(Convert.toStr(amount.get("currency")));
            }
            interlaceInternalTransferMapper.insert(interlaceInternalTransferDO);
        }
    }
}
